export default function BasedDescriptionHoc (Component, dataPropName) {
  let { getContent, ...props } = Component.props

  return {
    name: Component.name,
    // 基础组件的props对象
    props,
    data () {
      return {
        cacheObject: {}
      }
    },
    watch: {
      [dataPropName]: {
        handler () {
          this.cacheObject = {}
        },
        deep: true
      }
    },
    methods: {
      format (str, values) {
        /**
         * str: 字符串
         * values: 要替换的值数组
         */
        let rel = []

        values.forEach(item => {
          let r = /[$|@]\{(.*?)\}/

          if (typeof item !== 'object') {
            let matchLi = r.exec(str)

            if (matchLi) {
              // 匹配内层标识符
              let replaceStr = matchLi[1] && item ? matchLi[1].replace('$@', item) : item

              // 匹配外层标识符
              str = str.replace(r, replaceStr)
            }
          } else {
            let index = r.exec(str).index
            let length = r.exec(str)[0].length

            rel.push(str.slice(0, index))
            rel.push(item)
            str = str.slice(index + length)
          }
        })

        if (str) rel.push(str)

        return rel
      },
      getObjValue (o, key) {
        let keyList = key.split('.')
        let currentKey = keyList.shift();

        if (keyList.length) {
          if (!o[currentKey]) return ''
          else return this.getObjValue(o[currentKey], keyList.join('.'))
        } else {
          return o[currentKey]
        }
      },
      getContent (cacheKey, object, key, defaultOptions = { tag: 'div' }) {
        /**
         * cacheKey: 缓存键名， 可用 系数 + 关键字
         * object: 数据对象
         * key: 1. string 数据键名
         *      2. {
         *            modified: string，可格式化字符串， 如  "xxx: ${}, yyy: ${}"
         *            values: Array, 数据键名数组，将数据值依次填入 `modified`的 ${} 中
         *            empty: string 当数据值为空时
         *            default: string 当数据键名不存在数据对象时的值
         *         }
         */
        if (!key) return null

        if (cacheKey && this.cacheObject[cacheKey]) {
          return this.cacheObject[cacheKey]
        }

        let allOptions = null
        let { style: defaultStyle } = defaultOptions

        key = typeof key === 'string' ? { modified: '${}', values: [key] } : key
        if (typeof defaultStyle === 'object' && typeof key.style === 'object') {
          key = Object.assign({}, key, {
            style: Object.assign({}, defaultStyle, key.style)
          })
        }
        allOptions = Object.assign({}, defaultOptions, key)

        // if (allOptions.if && !this.getObjValue(object, allOptions.if)) return ''
        if (allOptions.if) {
          if (Array.isArray(allOptions.if)) {
            if (allOptions.if.every(item => !this.getObjValue(object, item))) return ''
          } else {
            if (!this.getObjValue(object, allOptions.if)) return ''
          }
        }

        let values = allOptions.values ? allOptions.values.map(item => {
          if (typeof item === 'string') {
            let val = this.getObjValue(object, item)

            if (val !== undefined && val !== null) val = val.toString()

            return val || (object.hasOwnProperty(item) ? allOptions.empty : allOptions.default) || ''
          } else {
            return this.getContent('', object, item)
          }
        }) : ''

        // 处理style
        if (typeof allOptions.style === 'function') {
          let styleFunc = allOptions.style

          allOptions.style = styleFunc(values)
        }

        // 格式拼接
        if (allOptions.join) {
          values = [values.filter(item => item).join(allOptions.join)]
        }

        let _on = {}
        if (allOptions.on) {
          for (let key in allOptions.on) {
            let fn = allOptions.on[key]

            _on[key] = (e) => fn(object, e)
          }
        }

        let VNode = this.$createElement(
          allOptions.tag,
          {
            style: allOptions.style,
            class: allOptions.class,
            key: allOptions.key,
            on: _on
          },
          Array.isArray(values) ? this.format(key.modified, values) : ''
        )

        if (cacheKey) this.cacheObject[cacheKey] = VNode

        return VNode
      }
    },
    render (h) {
      const props = Object.assign({}, this.$props, {
        getContent: this.getContent
      })

      return h(Component, {
        on: this.$listeners,
        nativeOn: this.$listeners,
        attrs: this.$attrs,
        // 将高阶组件接收到的props传递给基础组件
        props
      })
    }
  }
}
